package com.streamer.app.utils.http

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.gson.Gson
import com.youpai.yingteda_android.util.NetCode

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.net.ConnectException

fun <T> ViewModel.retrofit(dsl: RetrofitDSL<T>.() -> Unit) {
    //在主线程中开启协程
    viewModelScope.launch(Dispatchers.Main) {
        val coroutine = RetrofitDSL<T>().apply(dsl)
        coroutine.api?.let { call ->
            //async 并发执行 在IO线程中
            val deferred = viewModelScope.async(Dispatchers.IO) {
                try {
                    call.execute() //已经在io线程中了，所以调用Retrofit的同步方法
                } catch (e: Exception) {
                    e.printStackTrace() // 打印详细错误信息
                    if (e is ConnectException) {
                        withContext(Dispatchers.Main) {
                            val errorMsg = "cannot connect server: ${e.message}"
                            NetError.handleNetError(errorMsg, NetCode.ERROR_CODE_SERVER, )
                            coroutine.onFail?.invoke(
                                errorMsg,
                                NetCode.ERROR_CODE_CONNECTION
                            )
                        }
                    } else {
                        withContext(Dispatchers.Main) {
                            val errorMsg = "网络请求异常: ${e.message}"
                            NetError.handleNetError(errorMsg, NetCode.ERROR_CODE_CONNECTION, )
                            coroutine.onFail?.invoke(
                                errorMsg,
                                NetCode.ERROR_CODE_CONNECTION
                            )
                        }
                    }
                    null
                }
            }
            //当协程取消的时候，取消网络请求
            deferred.invokeOnCompletion {
                if (deferred.isCancelled) {
                    call.cancel()
                    coroutine.clean()
                }
            }
            //await 等待异步执行的结果
            val response = deferred.await()
            if (response == null) {
                val errorMsg = "网络异常，请切换网络。"
                NetError.handleNetError(errorMsg, NetCode.ERROR_CODE_REQUEST, )
                coroutine.onFail?.invoke(errorMsg, NetCode.ERROR_CODE_REQUEST)
            } else {
                response.let {
                    if (response.isSuccessful) {
                        //访问接口成功
                        val data = response.body()
                        if (data != null) {
                            if (data is BaseResult<*>) {
                                if (data.code == NetCode.ERROR_CODE_OK) {
                                    coroutine.onSuccess?.invoke(data)
                                } else {
                                    NetError.handleNetError(
                                        data.msg,
                                        data.code,

                                        coroutine.hideErrorToast?.invoke() != true
                                    )
                                    coroutine.onFail?.invoke(
                                        data.msg ?: "",
                                        NetCode.ERROR_CODE_SERVER
                                    )
                                }
                            }else if(data is PageDataResult<*>){
                                if (data.code == NetCode.ERROR_CODE_OK) {
                                    coroutine.onSuccess?.invoke(data)
                                } else {
                                    NetError.handleNetError(
                                        data.msg ?: "",
                                        data.code,

                                        coroutine.hideErrorToast?.invoke() != true
                                    )
                                    coroutine.onFail?.invoke(
                                        data.msg ,
                                        NetCode.ERROR_CODE_SERVER
                                    )
                                }
                            } else {
                                coroutine.onSuccess?.invoke(data)
//                                coroutine.onFail?.invoke(
//                                    "response data error",
//                                    NetCode.ERROR_CODE_SERVER
//                                )
                            }
                        } else {
                            val errorMsg = "response data error"
                            NetError.handleNetError(errorMsg, NetCode.ERROR_CODE_NO_BODY, )
                            coroutine.onFail?.invoke(
                                errorMsg,
                                NetCode.ERROR_CODE_NO_BODY
                            )
                        }
                    } else {
                        val errorBody = response.errorBody()
                        if (errorBody != null) {
                            try {
                                val result =
                                    Gson().fromJson(errorBody.string(), BaseResult::class.java)
                                result?.let {
                                    NetError.handleNetError(it.msg , it.code)
                                }
                            } catch (e: Exception) {
                                e.printStackTrace()
                                NetError.handleNetError(
                                    "data Error",
                                    NetCode.ERROR_CODE_SERVER,

                                )
                            }
                        }
                        val errorMsg = response.errorBody()?.string() ?: ""
                        NetError.handleNetError(errorMsg, response.code(), )
                        coroutine.onFail?.invoke(
                            errorMsg,
                            response.code()
                        )
                    }
                }
            }
            coroutine.onComplete?.invoke()
        }
    }


}